package com.hitqz.robot.biz.flow.component.patrol;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.hitqz.robot.api.business.enums.MediaEnum;
import com.hitqz.robot.api.business.model.dto.FlowContextDto;
import com.hitqz.robot.api.business.model.dto.FlowPatrolPreAndEndTicketsDto;
import com.hitqz.robot.api.business.model.dto.FlowPatrolTicketsDto;
import com.hitqz.robot.api.business.model.vo.patrol.PatrolItemVo;
import com.hitqz.robot.api.common.entity.*;
import com.hitqz.robot.biz.core.FileProperties;
import com.hitqz.robot.biz.flow.util.LiteFlowUtil;
import com.hitqz.robot.biz.service.PatrolCheckTypeService;
import com.hitqz.robot.biz.service.PatrolItemService;
import com.hitqz.robot.biz.service.PatrolObjectService;
import com.hitqz.robot.biz.service.RobotEquipmentService;
import com.hitqz.robot.camera.EquipmentFactory;
import com.hitqz.robot.camera.IEquipmentService;
import com.hitqz.robot.camera.configure.EquipmentCmdEnum;
import com.hitqz.robot.camera.dto.MediaFileDto;
import com.hitqz.robot.camera.dto.QueryParamsDto;
import com.hitqz.robot.camera.dto.TakePicParamsDto;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@LiteflowComponent(value = "TakePicByFfmpeg", name = "[巡检]通过ffmpeg拍照")
@AllArgsConstructor
public class TakePicByFfmpeg extends NodeComponent {

    private final RobotEquipmentService robotEquipmentService;

    private final EquipmentFactory equipmentFactory;

    private final PatrolItemService patrolItemService;

    private final FileProperties fileProperties;

    private final PatrolObjectService patrolObjectService;

    private final PatrolCheckTypeService patrolCheckTypeService;

    private final AtomicLong pid = new AtomicLong(-1);


    @Override
    public void process() throws Exception {
        FlowContextDto dto = this.getRequestData();
        TicketsTask task = dto.getTicketsTask();
        FlowPatrolTicketsDto params = JSONObject.parseObject(task.getParseOrderParams(), FlowPatrolTicketsDto.class);
        if (params.getDetectEquipmentId()==null){
            log.warn("没有检测设备信息,不执行");
            return;
        }
        PatrolItem currentPatrolItem = patrolItemService.getById(params.getPatrolItemId());
        PatrolObject currentPatrolObject = patrolObjectService.getById(currentPatrolItem.getPatrolObjectId());
        PatrolCheckType currentCheckType = patrolCheckTypeService.getById(currentPatrolObject.getPatrolCheckTypeId());
        MediaEnum mediaEnum = MediaEnum.getByType(currentCheckType.getMediaType());
        log.info("当前媒体类型:{},{}",currentCheckType,mediaEnum);
        if (isNeedSkip(dto)){
            //与上一次工单任务点位、姿态、相机相同,接下来判断媒体文件是否相同
            // 取媒体类型
            TicketsTask lastTask = dto.getLastTicketsTask();
            FlowPatrolTicketsDto lastParams = JSONObject.parseObject(lastTask.getParseOrderParams(), FlowPatrolTicketsDto.class);
            PatrolItem lastItem = patrolItemService.getById(lastParams.getPatrolItemId());
            PatrolObject lastPatrolObject = patrolObjectService.getById(lastItem.getPatrolObjectId());
            PatrolCheckType lastCheckType = patrolCheckTypeService.getById(lastPatrolObject.getPatrolCheckTypeId());
            if (Objects.equals(lastCheckType.getMediaType(), currentCheckType.getMediaType())){
                log.info("媒体类型相同");
                String lastMediaUrl = lastParams.getMediaUrl();
                params.setMediaUrl(lastMediaUrl);
                task.setParseOrderParams(JSONObject.toJSONString(params));
                log.info("跳过当前步骤");
                return;
            }
        }
        RobotEquipment camera = robotEquipmentService.getById(params.getDetectEquipmentId());
        // /日期/巡检对象
        PatrolItemVo item = patrolItemService.getVoById(params.getPatrolItemId());
        String folder ="patrol" + File.separator + DateUtil.format(new Date(),"yyyyMMdd")+ File.separator + item.getPatrolObjectStr();
        File folderFile = new File(folder);
        if (!folderFile.exists()){
            folderFile.mkdirs();
            log.info("创建目录:{}",folderFile);
        }
        //MediaFileDto mediaFileDto = service.takePic(channel.getIp(), channel.getChannel(), fileProperties.getLocal().getBasePath(), folder);
        String picName = "pic_" + DateUtil.format(new Date(),"yyyyMMddHHmmss") + ".jpg";
        String path  = fileProperties.getLocal().getBasePath() + File.separator + folder + File.separator + picName;
        String[] split = camera.getPlayUrl().split("source=");
        String rtsp = "";
        if (split.length > 1){
            rtsp = split[1];
        }
        boolean result = this.takePic(rtsp, path);
        log.info("ffmpeg 采集结果 {}", result);
        params.setMediaUrl(folder + File.separator + picName);
        //结果传递到上下文参数
        task.setParseOrderParams(JSONObject.toJSONString(params));
    }


    private boolean isNeedSkip(FlowContextDto dto){
        try {
            TicketsTask lastTicketsTask = dto.getLastTicketsTask();
            if (lastTicketsTask == null) {
                return false;
            }
            //当前参数
            TicketsTask task = dto.getTicketsTask();
            FlowPatrolTicketsDto params = JSONObject.parseObject(task.getParseOrderParams(), FlowPatrolTicketsDto.class);
            FlowPatrolPreAndEndTicketsDto endParams = JSONObject.parseObject(task.getParseOrderParams(), FlowPatrolPreAndEndTicketsDto.class);
            Integer currentTargetPosId = params.getPosId() != null ? params.getPosId() : (endParams.getEndPosId() != null ? endParams.getEndPosId() : null);
            //上一次的参数
            FlowPatrolTicketsDto lastParams = JSONObject.parseObject(lastTicketsTask.getParseOrderParams(), FlowPatrolTicketsDto.class);
            FlowPatrolPreAndEndTicketsDto lastEndParams = JSONObject.parseObject(lastTicketsTask.getParseOrderParams(), FlowPatrolPreAndEndTicketsDto.class);
            Integer lastTargetPosId = lastParams.getPosId() != null ? lastParams.getPosId() : (lastEndParams.getEndPosId() != null ? lastEndParams.getEndPosId() : null);
            if (!Objects.equals(currentTargetPosId,lastTargetPosId)){
                return false;
            }
            if (!Objects.equals(params.getPoseGroupId(),lastParams.getPoseGroupId())){
                return false;
            }
            if (!Objects.equals(params.getDetectEquipmentId(),lastParams.getDetectEquipmentId())){
                return false;
            }
            log.info("当前工单任务与上一次工单任务点位、姿态、相机相同");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private MediaFileDto transferMp4toWav(MediaFileDto mediaFileDto){
        String mp4Path = mediaFileDto.getAbsolutePath();
        String mp4Name = mediaFileDto.getName();
        String mp4RelativePath = mediaFileDto.getRelativePath();
        String wavName = mp4Name.replace(".mp4", ".wav");
        String wavFilePath = mp4Path.replace(mp4Name, wavName);
        String wavRelativePath = mp4RelativePath.replace(mp4Name, wavName);
        // 构建 ffmpeg 命令：从 MP4 提取音频并保存为 WAV
        String command = "ffmpeg -i " + mp4Path + " -vn -acodec pcm_s16le -ar 44100 -ac 2 " + wavFilePath;
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
            processBuilder.redirectErrorStream(true); // 合并标准错误和标准输出流
            Process process = processBuilder.start();
            int exitCode = process.waitFor();
            log.info("[HK]音频提取结束:{},{}",wavFilePath, exitCode);
        }catch (Exception e){
            log.error("[HK]音频提取失败",e);
        }

        File wavFile = new File(wavFilePath);
        if (wavFile.exists()) {
            log.info("[HK]生成 WAV 文件成功: {}", wavFilePath);
            // 可选：删除原始 MP4 文件
            log.info("[HK]删除原文件,{}", new File(mp4Path).delete());
        }
        MediaFileDto wavFileDto = new MediaFileDto();
        wavFileDto.setAbsolutePath(wavFilePath);
        wavFileDto.setName(mp4Name);
        wavFileDto.setRelativePath(wavRelativePath);
        return wavFileDto;
    }

    /**
     * rtsp 抓图
     *
     * @return 图片本地路径
     */
    private boolean takePic(String rtsp,String savePath) {
        if (StrUtil.isBlank(rtsp)){
            log.error("rtsp is blank");
            return false;
        }
        long start = System.currentTimeMillis();
        File file = new File(savePath);
        //fixme 优化拍照时间
        String command = "ffmpeg -f rtsp -rtsp_transport tcp -i " + rtsp + " -vframes 1 " + savePath;
        log.info("[ffmpeg]command: {}" , command);
        ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));

        try {
            Process process = processBuilder.start();
            pid.set(process.pid());
            CompletableFuture.runAsync(() -> {
                try {
                    //处理错误流
                    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                    String line;
                    // 即使没有在推流这个输出流仍然会输出数据，所以不能当做推流是否停止的标志
                    while ((line = reader.readLine()) != null && pid.get() != -1) {
                        log.error("[ffmpeg]error thread:{} " ,line);
                    }
                } catch (Exception e) {
                    log.error("[ffmpeg] error thread: {}" , e.getMessage());
                }
            });
            CompletableFuture.runAsync(() -> {
                try {
                    //处理错误流
                    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                    String line;
                    // 即使没有在推流这个输出流仍然会输出数据，所以不能当做推流是否停止的标志
                    while ((line = reader.readLine()) != null && pid.get() != -1) {
                        log.error("[ffmpeg]info thread:{} " ,line);
                    }
                } catch (Exception e) {
                    log.error("[ffmpeg]info thread error{} " , e.getMessage());
                }
            });
            int exitCode = process.waitFor();
            if (exitCode == 0 && file.exists()) {
                return true;
            }
        } catch (Exception e) {
            return false;
        } finally {
            long end = System.currentTimeMillis();
            log.info("抓图耗时:{} ms",(end - start));
        }
        return false;
    }


}